﻿using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using System;
using System.ComponentModel.Design;
using System.Globalization;
using Task = System.Threading.Tasks.Task;
using EnvDTE;
using EnvDTE80;

namespace DynamicMenu
{
    internal sealed class DynamicMenu
    {
        public const int CommandId = 0x0100;
        public static readonly Guid CommandSet = new Guid("f46b9bad-42a8-4ed7-bfc7-69f90f7a9866");
        private readonly AsyncPackage package;

        private static DTE2 dte2;

        private DynamicMenu(AsyncPackage package, OleMenuCommandService commandService)
        {
            this.package = package ?? throw new ArgumentNullException(nameof(package));
            commandService = commandService ?? throw new ArgumentNullException(nameof(commandService));

            var menuCommandID = new CommandID(CommandSet, CommandId);
            var menuItem = new MenuCommand(this.Execute, menuCommandID);
            commandService.AddCommand(menuItem);

            // 加在这里了 原文的 DynamicMenuPackageGuids 要替换为包的名称 DynamicMenuPackage
            // 添加动态项目菜单命令，以便在运行时将根项目扩展为n项。
            var dynamicItemRootId =
                new CommandID(new Guid(DynamicMenuPackage.guidDynamicMenuPackageCmdSet), (int)DynamicMenuPackage.cmdidMyCommand);
            var dynamicMenuCommand =
                new DynamicItemMenuCommand(dynamicItemRootId,
                IsValidDynamicItem,
                OnInvokedDynamicItem,
                OnBeforeQueryStatusDynamicItem);
            commandService.AddCommand(dynamicMenuCommand);

            dte2 = (DTE2)package.GetServiceAsync(typeof(DTE));
        }

        public static DynamicMenu Instance
        {
            get;
            private set;
        }

        private Microsoft.VisualStudio.Shell.IAsyncServiceProvider ServiceProvider
        {
            get
            {
                return this.package;
            }
        }

        public static async Task InitializeAsync(AsyncPackage package)
        {
            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);

            var commandService = await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService;
            Instance = new DynamicMenu(package, commandService);
        }

        private void Execute(object sender, EventArgs e)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            string message = string.Format(CultureInfo.CurrentCulture, "Inside {0}.MenuItemCallback()", this.GetType().FullName);
            string title = "DynamicMenu";

            //显示一个消息框以证明我们在这里
            VsShellUtilities.ShowMessageBox(
                this.package,
                message,
                title,
                OLEMSGICON.OLEMSGICON_INFO,
                OLEMSGBUTTON.OLEMSGBUTTON_OK,
                OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
        }

        /// <summary>
        /// 设置启动项目
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void OnInvokedDynamicItem(object sender, EventArgs args)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            var invokedCommand = (DynamicItemMenuCommand)sender;
            // 如果已经检查了该命令，我们无需做任何事情
            if (invokedCommand.Checked)
                return;

            //找到与命令文本对应的项目并将其设置为启动项目
            var projects = dte2.Solution.Projects;
            foreach (Project proj in projects)
            {
                if (invokedCommand.Text.Equals(proj.Name))
                {
                    dte2.Solution.SolutionBuild.StartupProjects = proj.FullName;
                    return;
                }
            }
        }

        /// <summary>
        /// 查询状态之前动态项目
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void OnBeforeQueryStatusDynamicItem(object sender, EventArgs args)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            var matchedCommand = (DynamicItemMenuCommand)sender;
            matchedCommand.Enabled = true;
            matchedCommand.Visible = true;

            //找出命令ID是否为0，这是根项的ID。
            //如果它是根项目，它匹配构造的动态项目菜单命令，
            //和有效的动态项目不会被调用。
            bool isRootItem = matchedCommand.MatchedCommandId == 0;

            // 索引设置为1而不是0，因为解决方案集合为1。
            int indexForDisplay = isRootItem ? 1 :
                matchedCommand.MatchedCommandId - (int)DynamicMenuPackage.cmdidMyCommand + 1;

            matchedCommand.Text = dte2.Solution.Projects.Item(indexForDisplay).Name;

            Array startupProjects = (Array)dte2.Solution.SolutionBuild.StartupProjects;
            string startupProject = System.IO.Path.GetFileNameWithoutExtension((string)startupProjects.GetValue(0));

            // 如果未选中已选中，请检查命令
            matchedCommand.Checked = matchedCommand.Text == startupProject;

            // 清除ID，因为我们完成了这个项目。
            matchedCommand.MatchedCommandId = 0;
        }

        /// <summary>
        /// 根据项目数处理
        /// </summary>
        /// <param name="commandId"></param>
        /// <returns></returns>
        private bool IsValidDynamicItem(int commandId)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            //如果命令ID为>=我们的根动态开始项的ID，则匹配是有效的
            //和命令ID减去我们根动态开始项的ID
            //小于或等于解决方案中的项目数。
            return (commandId >= (int)DynamicMenuPackage.cmdidMyCommand) &&
                  ((commandId - (int)DynamicMenuPackage.cmdidMyCommand) < dte2.Solution.Projects.Count);
        }

    }
}
